import Log from './log'

let log = new Log('dp>')

class DelayPromise {
  constructor(debug = false, delay = 100) {
    this._sync = {}
    this._keep = {}
    this._append = {}
    this._delay = delay
    this._debug = debug
  }

  genKey(key) {
    return key + '@' + Math.random()
  }

  prepare(key, keep = false) {
    let result = false

    if (this._debug) {
      log.w('prepare', key, keep)
    }

    if (keep) {
      const isKept = this.checkKeep(key)
      this._keep[key] = 1
      return isKept
    } else {
      delete this._sync[key]
    }

    return result
  }

  check(key) {
    return this._sync.hasOwnProperty(key)
  }

  checkKeep(key) {
    return this._keep.hasOwnProperty(key)
  }

  clear(key) {
    delete this._sync[key]
    delete this._keep[key]
  }

  _promise(key, resolve, reject) {
    const r = this._sync[key] || null

    if (!r.error || 0 === r.error) {
      resolve(r.data)
      if (this._debug) {
        log.w('resolved', key, r.data)
      }
    } else {
      reject(r)
      if (this._debug) {
        log.e('rejected', key, r)
      }
    }
  }

  keep(key) {
    return new Promise((resolve, reject) => {
      this._promise(key, resolve, reject)
    })
  }

  promise(key) {
    return new Promise((resolve, reject) => {
      let sid = setInterval(_ => {
        if (this._sync.hasOwnProperty(key)) {
          clearInterval(sid)

          if (!this._keep.hasOwnProperty(key)) {
            setTimeout(_ => {
              delete this._sync[key]
            }, this._delay)
          }

          this._promise(key, resolve, reject)
        }
      }, this._delay)
    })
  }

  done(key, error = null, data = null) {
    this._sync[key] = {error: error, data: data}
  }

  append(key, append) {
    if (this._append.hasOwnProperty(key)) {
      this._append[key].push(append)
    } else {
      this._append[key] = [append]
    }
  }

  appendDone(key, data = null) {
    const append = this._append[key] || []
    delete this._append[key]

    this._sync[key] = {error: null, data: {data: data, result: append}}
  }

  good(data = null) {
    return new Promise((r, _) => {
      r(data)

      if (this._debug) {
        log.w('good', data)
      }
    })
  }

  bad(reason = null) {
    return new Promise((_, e) => {
      e(reason)

      if (this._debug) {
        log.e('bad', reason)
      }
    })
  }

}

export default DelayPromise;
